﻿using System.Collections.Concurrent;
using System.Collections.Generic;

namespace UtilZ.Dotnet.Ex.DataStatistic
{
    /// <summary>
    /// 性能统计器
    /// </summary>
    public class PerformanceStatistic
    {
        private readonly static PerformanceStatistic _default = null;
        /// <summary>
        /// 默认统计器
        /// </summary>
        public static PerformanceStatistic Default
        {
            get { return _default; }
        }

        static PerformanceStatistic()
        {
            _default = new PerformanceStatistic();
        }




        private readonly ConcurrentDictionary<object, PerformanceStatisticItem> _statisticItemDic = new ConcurrentDictionary<object, PerformanceStatisticItem>();

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public PerformanceStatistic()
        {

        }

        /// <summary>
        /// 添加统计值
        /// </summary>
        /// <param name="key">统计标识key</param>
        /// <param name="value">统计值</param>
        public void Add(object key, double value)
        {
            PerformanceStatisticItem item;
            if (this._statisticItemDic.TryGetValue(key, out item))
            {
                item.Add(value);
            }
            else
            {
                lock (this._statisticItemDic)
                {
                    if (this._statisticItemDic.TryGetValue(key, out item))
                    {
                        item.Add(value);
                    }
                    else
                    {
                        item = new PerformanceStatisticItem(key);
                        item.Add(value);
                        this._statisticItemDic.TryAdd(key, item);
                    }
                }
            }
        }

        /// <summary>
        /// 移除指定统计标识的统计项
        /// </summary>
        /// <param name="key">统计标识key</param>
        public void Remove(object key)
        {
            PerformanceStatisticItem item;
            this._statisticItemDic.TryRemove(key, out item);
        }

        /// <summary>
        /// 清空统计项
        /// </summary>
        public void Clear()
        {
            this._statisticItemDic.Clear();
        }

        /// <summary>
        /// 清空统计历史结果
        /// </summary>
        public void ClearResult()
        {
            lock (this._statisticItemDic)
            {
                foreach (var item in this._statisticItemDic.Values)
                {
                    item.Clear();
                }
            }
        }

        /// <summary>
        /// 获取指定统计标识统计结果
        /// </summary>
        /// <param name="key">统计标识key</param>
        /// <returns>统计结果</returns>
        public PerformanceStatisticResult GetResultByKey(object key)
        {
            PerformanceStatisticItem item;
            if (this._statisticItemDic.TryGetValue(key, out item))
            {
                return item.GetResult();
            }
            else
            {
                return new PerformanceStatisticResult(key, 0, 0, 0, 0, 0);
            }
        }

        /// <summary>
        /// 获取所有统计结果
        /// </summary>
        /// <returns>统计结果</returns>
        public List<PerformanceStatisticResult> GetResults()
        {
            var list = new List<PerformanceStatisticResult>();
            foreach (var item in this._statisticItemDic.Values)
            {
                list.Add(item.GetResult());
            }
            return list;
        }

    }

    /// <summary>
    /// 性能统计器
    /// </summary>
    internal class PerformanceStatisticItem
    {
        private readonly object _key;
        private readonly ConcurrentBag<double> _values = new ConcurrentBag<double>();

        public PerformanceStatisticItem(object key)
        {
            this._key = key;
        }

        /// <summary>
        /// 添加统计值
        /// </summary>
        /// <param name="value">统计值</param>
        public void Add(double value)
        {
            this._values.Add(value);
        }

        /// <summary>
        /// 清空统计历史数据
        /// </summary>
        public void Clear()
        {
#if CORE
            this._values.Clear();
#else
            double value;
            while (this._values.TryTake(out value))
            {

            }
#endif
        }

        /// <summary>
        /// 获取统计结果
        /// </summary>
        /// <returns>统计结果</returns>
        public PerformanceStatisticResult GetResult()
        {
            double max, min, avg, trimAvg;
            int count;
            if (this._values.Count == 0)
            {
                max = 0d;
                min = 0d;
                avg = 0d;
                trimAvg = 0d;
                count = 0;
            }
            else
            {
                max = double.MinValue;
                min = double.MaxValue;
                double total = 0d;

                foreach (var value in this._values)
                {
                    if (value < min)
                    {
                        min = value;
                    }

                    if (value > max)
                    {
                        max = value;
                    }

                    total += value;
                }

                avg = total / this._values.Count;
                if (this._values.Count > 2)
                {
                    trimAvg = (total - min - max) / (this._values.Count - 2);
                }
                else
                {
                    trimAvg = avg;
                }
                count = this._values.Count;
            }

            return new PerformanceStatisticResult(this._key, max, min, avg, trimAvg, count);
        }


    }

    /// <summary>
    /// 性能统计结果
    /// </summary>
    public class PerformanceStatisticResult
    {
        /// <summary>
        /// 统计标识key
        /// </summary>
        public object Key { get; private set; }

        /// <summary>
        /// 最大值
        /// </summary>
        public double Max { get; private set; }

        /// <summary>
        /// 最小值
        /// </summary>
        public double Min { get; private set; }

        /// <summary>
        /// 平均值
        /// </summary>
        public double Avg { get; private set; }

        /// <summary>
        /// 截尾平均值
        /// </summary>
        public double TrimAvg { get; private set; }

        /// <summary>
        /// 统计次数
        /// </summary>
        public int Count { get; private set; }


        /// <summary>
        /// 构造函数初始化
        /// </summary>
        /// <param name="key">统计标识key</param>
        /// <param name="max">最大值</param>
        /// <param name="min">最小值</param>
        /// <param name="avg">平均值</param>
        /// <param name="trimAvg">截尾平均值</param>
        /// <param name="count">统计次数</param>
        public PerformanceStatisticResult(object key, double max, double min, double avg, double trimAvg, int count)
        {
            this.Key = key;
            this.Max = max;
            this.Min = min;
            this.Avg = avg;
            this.TrimAvg = trimAvg;
            this.Count = count;
        }

        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"MAx:{this.Max},Min:{this.Min},Avg:{this.Avg},TrimAvg:{this.TrimAvg}";
        }

    }
}
